﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BrightIdeasSoftware;
using ROrganizer.UI.Controllers;
using ROrganizer.UI.Forms.Core;
using ROrganizer.UI.Models;

namespace ROrganizer.UI.Forms
{
    internal partial class LibraryManagerForm : Form
    {
        private readonly LibraryManagerFormController controller;
        private readonly GroupManager<LibraryManagerFormController.Entry, object> groupper;

        public LibraryManagerForm()
        {
            this.controller = new LibraryManagerFormController();
            this.InitializeComponent();

            this.groupper = new GroupManager<LibraryManagerFormController.Entry, object>(this.olvFiles, null);
            this.InitializeGroups();

            this.olvFiles.ModelFilter = this.controller;
            this.olvFiles.UseFiltering = true;

            this.cbHideLinkedFiles.Checked = true;
            this.controller.HideLinkedFiles = true;
            this.olvFiles.Objects = this.controller.Entries;
            this.olvFiles.Sort(this.chName, SortOrder.Ascending);

            this.controller.Entries.CollectionChanged += this.OnChanged;
            this.controller.Changed += this.OnStateChanged;
        }

        private void InitializeGroups()
        {
            this.groupper.Bind(this.tsmiGroupByType, this.chType, null, order: SortOrder.Ascending);
            this.groupper.SetKey(this.chType, x => x.Type);

            this.groupper.Bind(this.tsmiGroupByFolder, this.chPath, null, order: SortOrder.Ascending);
            this.groupper.SetKey(this.chPath, x => x.Path);

            this.groupper.Bind(this.tsmiGroupByQuality, this.chResolution, order: SortOrder.Descending);
            this.groupper.SetKey(this.chResolution, x => Formatter.GetResolutionGroup(x.Resolution));
            this.groupper.SetFormat<Resolution>(this.chResolution, Formatter.FormatResolution);

            this.groupper.Bind(this.tsmiGroupBySize, this.chSize, order: SortOrder.Ascending);
            this.groupper.SetKey(this.chSize, x => Formatter.GetSizeGroup(x.Size));
            this.groupper.SetFormat<long>(this.chSize, Formatter.FormatSize);
            this.groupper.SetTitle<long>(this.chSize, Formatter.FormatSizeGroup);

            this.groupper.SetFormat<int?>(this.chResolution, Formatter.FormatResolutionGroup);
            this.groupper.SetFormat<int>(this.chRuntime, Formatter.FormatRuntime);
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            this.DialogResult = this.controller.IsChanged ? DialogResult.OK : DialogResult.Cancel;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.olvFiles.Normalize();
            this.tsbCommitChanges.Enabled = this.controller.CanCommitChanges();
        }

        private void OnChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (this.SynchronizeInvocation(this.OnChanged, sender, e))
            {
                if (e.Action == NotifyCollectionChangedAction.Reset)
                    this.olvFiles.ClearObjects();

                if (e.OldItems != null)
                    this.olvFiles.RemoveObjects(e.OldItems);

                if (e.NewItems != null)
                    this.olvFiles.AddObjects(e.NewItems);

                this.tsbCommitChanges.Enabled = this.controller.CanCommitChanges();
            }
        }

        private void OnStateChanged(object sender, EventArgs e)
        {
            this.olvFiles.BuildList(true);
        }

        private void OnManageFolders(object sender, EventArgs e)
        {
            this.ExecuteAndWatch(this.controller.ManageFolders, this);
        }

        private void OnCommitChanges(object sender, EventArgs e)
        {
            this.ExecuteAndWatch(this.controller.CommitChanges, this);
        }

        private void OnDoubleClick(object sender, MouseEventArgs e)
        {
            if (this.olvFiles.SelectedObject == null)
                return;

            this.ExecuteAndWatch(this.controller.ShowDetails, this, (LibraryManagerFormController.Entry)this.olvFiles.SelectedObject);
        }

        private void OnHideLinkedFilesChanged(object sender, EventArgs e)
        {
            this.controller.HideLinkedFiles = this.cbHideLinkedFiles.Checked;
            this.olvFiles.BuildList(true);
        }
    }
}
